import time
from datetime import datetime
from decimal import Decimal
from pony.orm import *
import mp4generator
import numpy as np
from PIL import Image, ImageFont, ImageDraw
import cv2 as cv
from queue import Queue
import threading as thread
from copy import deepcopy

db = Database()
db.bind(provider="mysql", host="61.171.67.58", user="maze_user", passwd="@WSXCDE#", db="maze")
set_sql_debug(True)

q = Queue()
colors = [
    (0xf5, 0xde, 0xb3),  # 未走过的路
    (0x8a, 0x2b, 0xe2),  # 墙壁
    (0xd3, 0xdb, 0x64),  # 当前位置
    (0x12, 0x8b, 0x37),  # 走过
    (0x32, 0x12, 0x8b),  # 重复经过
    (0xff, 0x00, 0x00),
    (0xff, 0x00, 0x00),
    (0xff, 0x00, 0x00),
    (0xff, 0x00, 0x00),
    (0xc4, 0xc4, 0xc4),  # 迷雾
    (0xff, 0x00, 0x00),
    (0x00, 0xff, 0xff),
    (0xff, 0xff, 0x00),
]


class MazeRecord(db.Entity):
    _table_ = "maze_record"
    maze_id = PrimaryKey(Decimal)
    maze_generator = Optional(str)
    maze_generator_version = Optional(str)
    start_position = Optional(Json)
    end_position = Optional(Json)
    maze = Optional(Json)
    maze_size = Optional(Json)


class MazeChallengeRecord(db.Entity):
    _table_ = "maze_challenge_record"
    record_id = PrimaryKey(Decimal)
    maze_id = Optional(int)
    maze_solver = Optional(str)
    maze_solver_version = Optional(str)


class MazeChallengeJourney(db.Entity):
    _table_ = "maze_challenge_journey"
    journey_id = PrimaryKey(Decimal)
    record_id = Optional(Decimal)
    current_position = Optional(Json)
    direction = Optional(str)
    is_start = Optional(bool)
    is_end = Optional(bool)
    step_order = Optional(int)
    create_time = Optional(datetime)


class MazeGenerateJourney(db.Entity):
    _table_ = "maze_generate_journey"
    journey_id = PrimaryKey(Decimal)
    maze_id = Optional(Decimal)
    current_position = Optional(Json)
    step_order = Optional(int)
    create_time = Optional(datetime)


class MyVideoSource(mp4generator.VideoSource):
    def __init__(self):
        self.img = np.full((41, 41, 3), (0xe2, 0x2b, 0x8a), dtype=np.uint8)
        self.background = np.full((738, 1312, 3), 255, dtype=np.uint8)
        self.text_bg = np.full((738, (1312 - 738), 3), 255, dtype=np.uint8)
        self.font = ImageFont.truetype("wqy/wqy-zenhei.ttc", 24)
        self._scale = 18
        size = self.img.shape
        # opencv's shape is y,x,channels
        self._size = (1312, 738)
        self.initTime = time.time()
        self.last_frame = self.img
        self.last_text = None
        self.frame_count = 0
        self.origin_maze = None
        self.generating = False

    def img_size(self):
        return self._size

    def fps(self):
        return 60

    def tips(self, img, position, line1, line2=None, line3=None, line4=None):
        imgPIL = Image.fromarray(cv.cvtColor(img, cv.COLOR_BGR2RGB))
        draw = ImageDraw.Draw(imgPIL)
        draw.text(position, line1, font=self.font, fill=(160, 255, 100))
        if line2 is not None:
            draw.text((41, 41 * 2), line2, font=self.font, fill=(128, 0, 128))
        if line3 is not None:
            draw.text((41, 41 * 3), line3, font=self.font, fill=(207, 207, 196))
        if line4 is not None:
            draw.text((41, 41 * 4), line4, font=self.font, fill=(207, 207, 196))
        del draw
        return cv.cvtColor(np.asarray(imgPIL), cv.COLOR_RGB2BGR)

    def zoom_cut(self, source, zoom):
        shape = source.shape
        dst = cv.resize(source, (shape[0] * zoom, shape[1] * zoom), interpolation=cv.INTER_NEAREST)
        return dst[int(shape[0] * zoom/2 - shape[0]/2):int(shape[0] * zoom/2 + shape[0]/2), int(shape[1] * zoom/2 - shape[1]/2):int(shape[1] * zoom/2 + shape[1]/2)]

    def generator(self):
        # 计算实时的帧率
        start_time = time.time()
        while True:
            for i in range(25):
                zoom = None
                frame = self.img
                text = np.copy(self.text_bg)
                if q.not_empty:
                    try:
                        data = q.get(timeout=1)  # timeout单位秒, 线程阻塞等待时间, None表示永远阻塞

                        continueTime = time.time() - self.initTime

                        # 计算帧率
                        end_time = time.time()
                        time_diff = end_time - start_time
                        real_fps = 1 / time_diff

                        im = data["im"]

                        resized_img = im.convert("RGB")
                        frame = cv.cvtColor(np.asarray(resized_img), cv.COLOR_RGB2BGR)

                        content = data["mazeSolver"]
                        mazeGenerator = data["mazeGenerator"]
                        solveTime = None
                        if data["solveTime"] is not None:
                            self.generating = False
                            solveTime = "Solved at " + datetime.fromtimestamp(data["solveTime"] / 1000).strftime("%X")
                        else:
                            self.generating = True
                            self.origin_maze = deepcopy(frame)
                        now = "Now " + datetime.now().strftime("%X")
                        receivedAt = "Received at " + data["receivedAt"]
                        step = data["step"] + " steps"
                        position = data["position"]
                        mps = data["mps"] + " mps"
                        sight = data["sightim"]
                        if 'zoom' in data:
                            zoom = data["zoom"]

                        self.frame_count += 1
                        print(str(self.frame_count), str(position["x"]), str(position["y"]))

                        line1 = mazeGenerator
                        if content is not None:
                            line1 = mazeGenerator + " vs " + content

                        line3 = receivedAt
                        if solveTime is not None:
                            line3 = solveTime + " - " + receivedAt

                        if line1 != "":
                            text = self.tips(
                                text,
                                (41, 41),
                                line1,
                                step + ", " + str(round(real_fps, 2)) + " fps, " + mps,
                                line3,
                                now + ", +" + str(int(continueTime)) + "s"
                            )

                            if sight is not None:
                                sight_img = sight.convert("RGB")
                                sight_img = cv.cvtColor(np.asarray(sight_img), cv.COLOR_RGB2BGR)
                                sight_img = cv.resize(sight_img, (3 * self._scale, 3 * self._scale), interpolation=cv.INTER_NEAREST)
                                text[41 * 5:41 * 5 + 3 * self._scale, 41:41 + 3 * self._scale, :] = sight_img
                    except Exception as e:
                        print(e)
                        pass

                try:
                    if zoom is not None:
                        frame = self.zoom_cut(frame, zoom)
                    # 放大到定义尺寸 16 : 9
                    frame = cv.resize(frame, (41 * self._scale, 41 * self._scale), interpolation=cv.INTER_NEAREST)
                    self.background[0:41 * self._scale, 0:41 * self._scale, :] = frame
                    self.background[0:41 * self._scale, 41 * self._scale:1312, :] = text

                    # 寻路的时候, 显示生成的完整迷宫
                    if not self.generating and self.origin_maze is not None:
                        resized_origin_maze = cv.resize(self.origin_maze, (41 * 3, 41 * 3),
                                                        interpolation=cv.INTER_NEAREST)
                        y1 = 41 * self._scale - 41 * 4
                        y2 = 41 * self._scale - 41
                        x1 = 41 * self._scale + int((1312 - 41 * (self._scale + 3)) / 2)
                        x2 = x1 + 41 * 3
                        self.background[y1:y2, x1:x2, :] = resized_origin_maze
                        del resized_origin_maze

                    if self.background is None:
                        print("background is None")

                    yield self.background
                except Exception as e:
                    print(e)
                    pass

                start_time = time.time()

                # 单位是秒, 如果设置为1, 则等待1秒, 这样会影响视频帧率, 1秒1帧
                time.sleep(0.016)
            # for i in range(1, 500, 1):
            # processes the image a little bit
            # x = abs(50-i)
            # yield cv.blur(self.img,(x,x))
            # fn = "%06d" % i
            # yield cv.imread("/home/xlj/1710302140578349058/multi_ze_" + fn + ".png")


@db_session
def gen_maze(name, recordId=None):

    records = MazeChallengeRecord.select_by_sql(
        "SELECT record_id, maze_id, maze_solver "
        "FROM maze_challenge_record "
        "WHERE record_id = $recordId",
        globals={"recordId": recordId}
    )
    record = records.pop()
    mazeId = record.maze_id

    mazes = MazeRecord.select_by_sql(
        sql="SELECT maze_id, maze, maze_generator "
        "FROM maze_record "
        "WHERE maze_id = $mazeId",
        globals={'mazeId': mazeId}
    )

    maze = mazes.pop()

    generates = MazeGenerateJourney.select_by_sql(
        "SELECT journey_id, current_position, step_order, create_time "
        "FROM maze_generate_journey "
        "WHERE maze_id = $mazeId "
        "ORDER BY step_order ASC",
        globals={"mazeId": maze.maze_id}
    )[:]

    def run():
        time.sleep(3)

        mazeData = np.full((41, 41), 1, dtype="int8")

        im = Image.fromarray(mazeData)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": maze.maze_generator,
            "mazeSolver": None,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "mps": str(60)
        })

        for generate in generates:
            current = dict(generate.current_position)
            x = current["x"]
            y = current["y"]
            mazeData[y, x] = 0

            imstep = Image.fromarray(mazeData)
            imstep = imstep.convert('P')  # P代表索引图片
            imstep.putpalette(palette)

            step = generate.step_order
            q.put({
                "im": imstep,
                "mazeGenerator": maze.maze_generator,
                "mazeSolver": None,
                "solveTime": None,
                "receivedAt": datetime.now().strftime("%X"),
                "step": str(step),
                "sightim": None,
                "mps": str(60)
            })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/{}_{}.mp4".format(recordId, maze.maze_generator), 1280, 720, fps=60)
    fvd.run()


@db_session
def gen_path_finding(name, recordId=None):

    records = MazeChallengeRecord.select_by_sql(
        "SELECT record_id, maze_id, maze_solver "
        "FROM maze_challenge_record "
        "WHERE record_id = $recordId",
        globals={"recordId": recordId}
    )
    record = records.pop()
    mazeId = record.maze_id
    mazeSolver = record.maze_solver

    mazes = MazeRecord.select_by_sql(
        sql="SELECT maze_id, maze, maze_generator "
        "FROM maze_record "
        "WHERE maze_id = $mazeId",
        globals={'mazeId': mazeId}
    )

    maze = mazes.pop()

    journeys = MazeChallengeJourney.select_by_sql(
        "SELECT journey_id, current_position, direction, create_time "
        "FROM maze_challenge_journey "
        "WHERE record_id = $recordId "
        "ORDER BY journey_id asc",
        globals={"recordId": recordId}
    )[:]

    def run():
        time.sleep(3)

        mazeData = np.array(maze.maze, dtype='int8')

        im = Image.fromarray(mazeData)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": maze.maze_generator,
            "mazeSolver": mazeSolver,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "sightim": None,
            "mps": str(60)
        })

        last = None
        step = 1
        for journey in journeys:
            current = dict(journey.current_position)
            x = current["x"]
            y = current["y"]
            mazeData[y, x] = 2
            if last is not None:
                mazeData[last["y"], last["x"]] = 3
            last = current

            sightim = None
            if y - 1 >= 0 and x - 1 >= 0:
                sight = mazeData[(y-1):(y+2), (x-1):(x+2)]
                sightim = Image.fromarray(sight)
                sightim = sightim.convert('P')  # P代表索引图片
                sightim.putpalette(palette)

            imstep = Image.fromarray(mazeData)
            imstep = imstep.convert('P')  # P代表索引图片
            imstep.putpalette(palette)

            step += 1
            q.put({
                "im": imstep,
                "mazeGenerator": maze.maze_generator,
                "position": journey.current_position,
                "mazeSolver": mazeSolver,
                "solveTime": int(journey.create_time.strftime("%Y%m%d%H%M%S")),
                "receivedAt": datetime.now().strftime("%X"),
                "step": str(step),
                "sightim": sightim,
                "mps": str(60)
            })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/{}_{}.mp4".format(recordId, mazeSolver), 1280, 720, fps=60)
    fvd.run()


@db_session
def gen_path_finding_road(name, recordId=None):

    records = MazeChallengeRecord.select_by_sql(
        "SELECT record_id, maze_id, maze_solver "
        "FROM maze_challenge_record "
        "WHERE record_id = $recordId",
        globals={"recordId": recordId}
    )
    record = records.pop()
    mazeId = record.maze_id
    mazeSolver = record.maze_solver

    mazes = MazeRecord.select_by_sql(
        sql="SELECT maze_id, maze, maze_generator "
        "FROM maze_record "
        "WHERE maze_id = $mazeId",
        globals={'mazeId': mazeId}
    )

    maze = mazes.pop()

    journeys = MazeChallengeJourney.select_by_sql(
        "SELECT journey_id, current_position, direction, create_time "
        "FROM maze_challenge_journey "
        "WHERE record_id = $recordId "
        "ORDER BY journey_id asc",
        globals={"recordId": recordId}
    )[:]

    def run():
        time.sleep(3)

        mazeData = np.array(maze.maze, dtype='int8')
        fogMaze = np.full((41, 41), 1, dtype="int8")
        fogMaze[1:40, 1:40] = 9

        im = Image.fromarray(fogMaze)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": maze.maze_generator,
            "mazeSolver": mazeSolver,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "mps": str(60)
        })

        last = None
        step = 1
        for journey in journeys:
            current = dict(journey.current_position)
            x = current["x"]
            y = current["y"]
            fogMaze[y, x] = 2
            if last is not None:
                fogMaze[last["y"], last["x"]] = 3
            last = current

            sightim = None
            if y - 1 >= 0 and x - 1 >= 0:
                sight = mazeData[(y-1):(y+2), (x-1):(x+2)]
                sightim = Image.fromarray(sight)
                sightim = sightim.convert('P')  # P代表索引图片
                sightim.putpalette(palette)

            imstep = Image.fromarray(fogMaze)
            imstep = imstep.convert('P')  # P代表索引图片
            imstep.putpalette(palette)

            step += 1
            q.put({
                "im": imstep,
                "mazeGenerator": maze.maze_generator,
                "position": journey.current_position,
                "mazeSolver": mazeSolver,
                "solveTime": int(journey.create_time.strftime("%Y%m%d%H%M%S")),
                "receivedAt": datetime.now().strftime("%X"),
                "step": str(step),
                "sightim": sightim,
                "mps": str(60)
            })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/{}_{}_road.mp4".format(recordId, mazeSolver), 1280, 720, fps=60)
    fvd.run()


@db_session
def gen_path_finding_in_fog(name, recordId=None):

    records = MazeChallengeRecord.select_by_sql(
        "SELECT record_id, maze_id, maze_solver "
        "FROM maze_challenge_record "
        "WHERE record_id = $recordId",
        globals={"recordId": recordId}
    )
    record = records.pop()
    mazeId = record.maze_id
    mazeSolver = record.maze_solver

    mazes = MazeRecord.select_by_sql(
        sql="SELECT maze_id, maze, maze_generator "
        "FROM maze_record "
        "WHERE maze_id = $mazeId",
        globals={'mazeId': mazeId}
    )

    maze = mazes.pop()

    journeys = MazeChallengeJourney.select_by_sql(
        "SELECT journey_id, current_position, direction, create_time "
        "FROM maze_challenge_journey "
        "WHERE record_id = $recordId "
        "ORDER BY journey_id asc",
        globals={"recordId": recordId}
    )[:]

    def run():
        time.sleep(3)

        mazeData = np.array(maze.maze, dtype='int8')
        fogMaze = np.full((41, 41), 1, dtype="int8")
        fogMaze[1:40, 1:40] = 9

        im = Image.fromarray(fogMaze)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": maze.maze_generator,
            "mazeSolver": mazeSolver,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "mps": str(60)
        })

        last = None
        step = 1
        for journey in journeys:
            current = dict(journey.current_position)
            x = current["x"]
            y = current["y"]
            mazeData[y, x] = 2
            if last is not None:
                mazeData[last["y"], last["x"]] = 3
            last = current

            sightim = None
            if y - 1 >= 0 and x - 1 >= 0:
                sight = mazeData[(y-1):(y+2), (x-1):(x+2)]
                sightim = Image.fromarray(sight)
                sightim = sightim.convert('P')  # P代表索引图片
                sightim.putpalette(palette)

                # 复制视野
                fogMaze[(y-1):(y+2), (x-1):(x+2)] = sight

            imstep = Image.fromarray(fogMaze)
            imstep = imstep.convert('P')  # P代表索引图片
            imstep.putpalette(palette)

            step += 1
            q.put({
                "im": imstep,
                "mazeGenerator": maze.maze_generator,
                "position": journey.current_position,
                "mazeSolver": mazeSolver,
                "solveTime": int(journey.create_time.strftime("%Y%m%d%H%M%S")),
                "receivedAt": datetime.now().strftime("%X"),
                "step": str(step),
                "sightim": sightim,
                "mps": str(60)
            })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/{}_{}-inFog.mp4".format(recordId, mazeSolver), 1280, 720, fps=60)
    fvd.run()


@db_session
def gen_path_finding_in_focus(name, recordId=None):

    records = MazeChallengeRecord.select_by_sql(
        "SELECT record_id, maze_id, maze_solver "
        "FROM maze_challenge_record "
        "WHERE record_id = $recordId",
        globals={"recordId": recordId}
    )
    record = records.pop()
    mazeId = record.maze_id
    mazeSolver = record.maze_solver

    mazes = MazeRecord.select_by_sql(
        sql="SELECT maze_id, maze, maze_generator "
        "FROM maze_record "
        "WHERE maze_id = $mazeId",
        globals={'mazeId': mazeId}
    )

    maze = mazes.pop()

    journeys = MazeChallengeJourney.select_by_sql(
        "SELECT journey_id, current_position, direction, create_time "
        "FROM maze_challenge_journey "
        "WHERE record_id = $recordId "
        "ORDER BY journey_id asc",
        globals={"recordId": recordId}
    )[:]

    def run():
        time.sleep(3)
        background = np.full((41, 41), 9, dtype="int8")

        mazeData = np.array(maze.maze, dtype='int8')
        fogMaze = np.full((41, 41), 1, dtype="int8")
        fogMaze[1:40, 1:40] = 9

        def neg_to_zero(value):
            if value < 0:
                return 0
            return value

        def pos_to_max(value):
            if value > 41:
                return 41
            return value

        def move(fromPos, toPos):
            fromXI = neg_to_zero(fromPos["x"] - toPos["x"])
            fromYI = neg_to_zero(fromPos["y"] - toPos["y"])
            fromX2I = pos_to_max(fromPos["x"] + 41 - toPos["x"])
            fromY2I = pos_to_max(fromPos["y"] + 41 - toPos["y"])
            toXI = neg_to_zero(toPos["x"] - fromPos["x"])
            toYI = neg_to_zero(toPos["y"] - fromPos["y"])
            toX2I = pos_to_max(toPos["x"] + 41 - fromPos["x"])
            toY2I = pos_to_max(toPos["y"] + 41 - fromPos["y"])

            return fromXI, fromYI, fromX2I, fromY2I, toXI, toYI, toX2I, toY2I

        # 把迷宫当前位置对齐到背景的中央 [20, 20]
        center = {"x": 20, "y": 20}
        frame = np.copy(background)
        current = {"x": 0, "y": 1}

        fromX, fromY, fromX2, fromY2, toX, toY, toX2, toY2 = move(current, center)
        frame[toY:toY2, toX:toX2] = fogMaze[fromY:fromY2, fromX:fromX2]

        im = Image.fromarray(frame)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": maze.maze_generator,
            "mazeSolver": mazeSolver,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "sightim": None,
            "mps": str(60)
        })

        last = None
        step = 1
        for journey in journeys:
            current = dict(journey.current_position)
            x = current["x"]
            y = current["y"]
            mazeData[y, x] = 2
            if last is not None:
                mazeData[last["y"], last["x"]] = 3
            last = current

            sightim = None
            if y - 1 >= 0 and x - 1 >= 0:
                sight = mazeData[(y-1):(y+2), (x-1):(x+2)]
                sightim = Image.fromarray(sight)
                sightim = sightim.convert('P')  # P代表索引图片
                sightim.putpalette(palette)

                # 复制视野
                fogMaze[(y-1):(y+2), (x-1):(x+2)] = sight

            frame = np.copy(background)
            fromX, fromY, fromX2, fromY2, toX, toY, toX2, toY2 = move(current, center)
            frame[toY:toY2, toX:toX2] = fogMaze[fromY:fromY2, fromX:fromX2]

            imstep = Image.fromarray(frame)
            imstep = imstep.convert('P')  # P代表索引图片
            imstep.putpalette(palette)

            step += 1
            q.put({
                "im": imstep,
                "mazeGenerator": maze.maze_generator,
                "position": journey.current_position,
                "mazeSolver": mazeSolver,
                "solveTime": int(journey.create_time.strftime("%Y%m%d%H%M%S")),
                "receivedAt": datetime.now().strftime("%X"),
                "step": str(step),
                "sightim": sightim,
                "mps": str(60)
            })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/{}_{}-inFocus.mp4".format(recordId, mazeSolver), 1280, 720, fps=60)
    fvd.run()


@db_session
def gen_path_finding_in_focus_half(name, recordId=None):

    records = MazeChallengeRecord.select_by_sql(
        "SELECT record_id, maze_id, maze_solver "
        "FROM maze_challenge_record "
        "WHERE record_id = $recordId",
        globals={"recordId": recordId}
    )
    record = records.pop()
    mazeId = record.maze_id
    mazeSolver = record.maze_solver

    mazes = MazeRecord.select_by_sql(
        sql="SELECT maze_id, maze, maze_generator "
        "FROM maze_record "
        "WHERE maze_id = $mazeId",
        globals={'mazeId': mazeId}
    )

    maze = mazes.pop()

    journeys = MazeChallengeJourney.select_by_sql(
        "SELECT journey_id, current_position, direction, create_time "
        "FROM maze_challenge_journey "
        "WHERE record_id = $recordId "
        "ORDER BY journey_id asc",
        globals={"recordId": recordId}
    )[:]

    def run():
        time.sleep(3)
        background = np.full((41, 41), 9, dtype="int8")

        mazeData = np.array(maze.maze, dtype='int8')
        fogMaze = np.full((41, 41), 1, dtype="int8")
        fogMaze[1:40, 1:40] = 9

        def neg_to_zero(value):
            if value < 0:
                return 0
            return value

        def pos_to_max(value):
            if value > 41:
                return 41
            return value

        def move(fromPos, toPos):
            fromXI = neg_to_zero(fromPos["x"] - toPos["x"])
            fromYI = neg_to_zero(fromPos["y"] - toPos["y"])
            fromX2I = pos_to_max(fromPos["x"] + 41 - toPos["x"])
            fromY2I = pos_to_max(fromPos["y"] + 41 - toPos["y"])
            toXI = neg_to_zero(toPos["x"] - fromPos["x"])
            toYI = neg_to_zero(toPos["y"] - fromPos["y"])
            toX2I = pos_to_max(toPos["x"] + 41 - fromPos["x"])
            toY2I = pos_to_max(toPos["y"] + 41 - fromPos["y"])

            return fromXI, fromYI, fromX2I, fromY2I, toXI, toYI, toX2I, toY2I

        # 把迷宫当前位置对齐到背景的中央 [20, 20]
        center = {"x": 20, "y": 20}
        frame = np.copy(background)
        current = {"x": 0, "y": 1}

        fromX, fromY, fromX2, fromY2, toX, toY, toX2, toY2 = move(current, center)
        frame[toY:toY2, toX:toX2] = fogMaze[fromY:fromY2, fromX:fromX2]

        im = Image.fromarray(frame)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": maze.maze_generator,
            "mazeSolver": mazeSolver,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "sightim": None,
            "mps": str(60),
            "zoom": 3
        })

        last = None
        step = 1
        for journey in journeys:
            current = dict(journey.current_position)
            x = current["x"]
            y = current["y"]
            mazeData[y, x] = 2
            if last is not None:
                mazeData[last["y"], last["x"]] = 3
            last = current

            sightim = None
            if y - 1 >= 0 and x - 1 >= 0:
                sight = mazeData[(y-1):(y+2), (x-1):(x+2)]
                sightim = Image.fromarray(sight)
                sightim = sightim.convert('P')  # P代表索引图片
                sightim.putpalette(palette)

                # 复制视野
                fogMaze[(y-1):(y+2), (x-1):(x+2)] = sight

            frame = np.copy(background)
            fromX, fromY, fromX2, fromY2, toX, toY, toX2, toY2 = move(current, center)
            frame[toY:toY2, toX:toX2] = fogMaze[fromY:fromY2, fromX:fromX2]

            imstep = Image.fromarray(frame)
            imstep = imstep.convert('P')  # P代表索引图片
            imstep.putpalette(palette)

            step += 1
            q.put({
                "im": imstep,
                "mazeGenerator": maze.maze_generator,
                "position": journey.current_position,
                "mazeSolver": mazeSolver,
                "solveTime": int(journey.create_time.strftime("%Y%m%d%H%M%S")),
                "receivedAt": datetime.now().strftime("%X"),
                "step": str(step),
                "sightim": sightim,
                "mps": str(60),
                "zoom": 3
            })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/{}_{}-inHalfFocus.mp4".format(recordId, mazeSolver), 1280, 720, fps=60)
    fvd.run()


def gen_training():

    def run():
        time.sleep(3)
        mazeData = np.full((41, 41), 1, dtype="int8")

        mazeData[1::2, 1::2] = 0
        im = Image.fromarray(mazeData)
        im = im.convert('P')  # P代表索引图片
        palette = np.array(colors).reshape(-1).tolist()
        im.putpalette(palette)

        q.put({
            "im": im,
            "mazeGenerator": "",
            "mazeSolver": None,
            "solveTime": None,
            "receivedAt": datetime.now().strftime("%X"),
            "step": str(0),
            "mps": str(60)
        })

    thread.Thread(target=run).start()

    vidsrc = MyVideoSource()
    fvd = mp4generator.FakeVideoDevice()
    fvd.init_input(vidsrc)
    fvd.init_output("/home/xlj/视频/演示.mp4", 1280, 720, fps=60)
    fvd.run()


if __name__ == '__main__':

    # gen_training()

    db.generate_mapping(create_tables=False)
    # mazeGenerating = True
    mazeGenerating = False
    recordId = 1716355413441757185

    if mazeGenerating:
        gen_maze('PyCharm', recordId=recordId)
    else:
        # gen_path_finding('PyCharm', recordId=recordId)
        # gen_path_finding_road('PyCharm', recordId=recordId)
        # gen_path_finding_in_fog('PyCharm', recordId=recordId)
        # gen_path_finding_in_focus('PyCharm', recordId=recordId)
        gen_path_finding_in_focus_half('PyCharm', recordId=recordId)
